package com.qf.smartplatform.websocket;




import com.qf.smartplatform.events.CommandEvent;
import com.qf.smartplatform.events.DeviceOnOffLineEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

//@Controller
public class MyBaseCommandHandler extends TextWebSocketHandler {

    private ApplicationContext context;

    @Autowired
    public void setContext(ApplicationContext context) {
        this.context = context;
    }

    private static Map<String, WebSocketSession> allClients = new HashMap<>();//保存有所有客户端的map对象

    private static Map<String, Long> allClientLastHeartbeat = new HashMap<>();

    public static Map<String, WebSocketSession> getAllClients() {
        return allClients;
    }

    public static Map<String, Long> getAllClientLastHeartbeat() {
        return allClientLastHeartbeat;
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        //把连接保存起来
        String uri = session.getUri().toString();//请求的地址
        //地址的最后一位是设备的标识
        String deviceId = uri.substring(uri.lastIndexOf("/") + 1);
        WebSocketSession currentSesion = allClients.get(deviceId);
        if (currentSesion != null) {
            currentSesion.close();//设备多次连接的情况下,先关闭原先的连接,减少资源的占用
        }

        session.getAttributes().put("id", deviceId);//保存到会话中,方便下次使用,不用每次都裁减字符串
        allClients.put(deviceId, session);//将设备的链接保存起来
        System.err.println("设备" + deviceId + "连接成功");
        allClientLastHeartbeat.put(deviceId, System.currentTimeMillis());//保存设备的最后一次连接时间(心跳时间)
        context.publishEvent(new DeviceOnOffLineEvent(deviceId, new Date(), session.getRemoteAddress().getHostString(), 1L));

        super.afterConnectionEstablished(session);
    }

    // humiture/id
    //{"humidity":"","temperature":""}
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        super.handleTextMessage(session, message);
        Object id = session.getAttributes().get("id");//设备的id
        //这里设备每个一段时间会给我们发送心跳数据,我们约定心跳数据叫ping,实际上可以发送空字符串,内容不重要,只关注是不是发送了
        String payload = message.getPayload();//获取到设备发送过来的内容
        System.err.println("收到设备:" + id + " 发来的数据:==>" + payload);
       // if ("ping".equalsIgnoreCase(payload)) {
            //这是心跳数据,按照上面的说法,设备不管发送什么数据给我们,其实都是相当于心跳
            allClientLastHeartbeat.put((String) id, System.currentTimeMillis());//给设备更新最后的心跳时间,map的特点,同一个key数据会覆盖,所以只会保存最后一次数据
      //  }
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        // super.afterConnectionClosed(session, status);
        context.publishEvent(new DeviceOnOffLineEvent((String) session.getAttributes().get("id"), new Date(), null, 2L));

    }

    //    @EventListener
//    @Async
    public static void sendControl(CommandEvent event) {
        Object command = event.getCommand();
        String uid = event.getUid();
        WebSocketSession session = allClients.get(uid);//根据设备的id来获取到链接
        if (session != null && session.isOpen()) {
            try {
                session.sendMessage(new TextMessage(command.toString()));//发送命令
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    public static void checkStatus() {
        CompletableFuture.runAsync(() -> {
            HashMap<String, Long> hashMap = new HashMap<>();
            hashMap.putAll(allClientLastHeartbeat);//为了能够在里面一边遍历一边删除,我们使用了一个临时的map保存了所有的数据
            hashMap.forEach((id, time) -> {
                long currentTimeMillis = System.currentTimeMillis();
                if (currentTimeMillis - time >= 60000) {//超出了我们设定的阈值,60000是我们自己的约定
                    //已经多次没有发送心跳数据,可以认定设备离线
                    //关闭会话
                    System.err.println("设备:" + id + "已经离线了");
                    WebSocketSession socketSession = allClients.get(id);//以设备的编号为key,获取到回话
                    if (socketSession != null && socketSession.isOpen()) {
                        try {
                            socketSession.close();//关闭会话,会触发上面的关闭方法,在内部会将设备变更为离线
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    allClients.remove(id);
                    allClientLastHeartbeat.remove(id);//会不会出现一边遍历一边删除的情况?
                }
            });
            hashMap.clear();
        });
    }
}
